class ServeManager {
  constructor({
    messageUrl = "",
    id = "",
    data = {},
    pingTimeOut = 8000,
    pongTimeOut = 15000,
    pingMsg = 'heartbeat',
    reconnectLimit = 1000,
    reconnectTimeOut = 5000
  } = {}) {
    if (typeof ServeManager.instance === 'object') {
      return ServeManager.instance;
    }
    ServeManager.instance = this;
    this._instance = null;

    this.messageUrl = messageUrl; // websocket 连接地址
    this.id = id; // websocket 链接唯一标识
    this.data = data; // 包含 app、branch、corporation 信息

    this.pingTimeOut = pingTimeOut; // 每隔 pingTimeOut 毫秒发送一条心跳请求
    this.pongTimeOut = pongTimeOut; // 最长未接收消息的间隔，在心跳请求发送 pongTimeOut 毫秒内未收到响应关闭连接
    this.pingMsg = pingMsg // 心跳消息内容

    this.reconnecting = false; // 是否处于重连状态
    this.reconnectCount = 0; // 当前的重连次数
    this.reconnectTimer = null; // 重连定时器
    this.reconnectLimit = reconnectLimit; // 最大重连次数，默认 10
    this.reconnectTimeOut = reconnectTimeOut; // 发起重连的间隔，避免请求过多
  }

  init() {
    this._instance = new WebSocket(this.messageUrl);
    this._instance.onopen = (e) => {
      this.onopen(e);
    };
    // 接收到 websocket 推送的消息时触发
    this._instance.onmessage = (e) => {
      this.onmessage(e);
    };
    // 通信发生错误时触发
    this._instance.onerror = (e) => {
      this.onerror(e);
    };
    // 通信关闭时触发
    this._instance.onclose = (e) => {
      this.onclose(e);
    };
  }

  onopen() {
    this.reconnectCount = 0;
    this.reconnecting = false;

    clearTimeout(this.reconnectTimer);

    let initObj = {
      type: 'init',
      id: this.id,
      data: this.data
    };

    this._instance.send(JSON.stringify(initObj));
    // 初始化连接时就发心跳
    this.heartCheck();
  }

  onmessage(e) {
    // 如果接受的数据是心跳数据,则不进行操作
    if (e.data === this.pingMsg) {
      this.heartCheck();
      return;
    };
    // 节点信息已被注册
    if (e.data === "[节点信息已被注册，您已被强制下线]") {
      this._instance.onclose();
      return;
    }
    // 获得交易画面的数据
    if (e.data) {
      let data = JSON.parse(e.data);
      if (data.data) {
        loadPageData(data);
      }
      let ackData = {
        type: 'ack',
        msgId: data.msgId
      };
      this._instance.send(JSON.stringify(ackData));
    }
    // 获得消息, 心跳检测重置
    this.heartCheck();
  }

  onerror(e) {
    // 如果发生错误,执行重连操作
    this.reconnect();
  }

  onclose(e) {
    // 如果不是手动关闭,则执行重连操作
    this.reconnect();
  }
  // 心跳操作的方法，每隔 pingTimeOut 毫秒发送一条心跳请求；在心跳请求发送 pongTimeOut 毫秒内未收到响应关闭连接
  heartCheck() {
    clearTimeout(this.pingTimeoutId);
    clearTimeout(this.pongTimeoutId);
    this.pingTimeoutId = setTimeout(() => {
      // 发送一个心跳请求
      this._instance.send(this.pingMsg);
      this.pongTimeoutId = setTimeout(() => {
        // 如果长时间后端没返回,则尝试关闭并重连
        this._instance.onclose();
      }, this.pongTimeOut);
    }, this.pingTimeOut);
  }
  // 重连操作的方法
  reconnect() {
    if (this.reconnecting) return;
    if (this.reconnectCount > this.reconnectLimit) {
      return;
    };

    this.reconnecting = true;
    this.reconnectCount++;
    this.init();

    this.reconnectTimer = setTimeout(() => {
      this.reconnecting = false;
      this.reconnect();
    }, this.reconnectTimeOut);
  };
}

export default ServeManager;

/**
 * 使用
 * const ServeManager = new require('./xxxx')
 * ServeManager.init()
 */
